本來預期上篇就可以把 CRUD 做完,實際試下去,才知道 bee 這工具不如預期來的好。今天除了簡單的介紹 Template 之外,也順便實作出使用者列表頁面。
言歸正傳,BeeGo 的 Template 是直接使用 Go 的 Template 模組,所以語法是一樣的。
當 Controller 裡用
c.Data["Name"] = "John Doe"
要取用變數時,就是用
{{.Name}}
當變數是 list/slice/map 時,可以用 range
<!-- map -->
{{range $key, $val := .object_map}}
<p>{{$key}}:{{$val}}</p>
{{end}}
<!-- list/slice -->
{{range $object := .object_list}}
<p>{{$object.Name}}</p>
{{end}}
要做條件式的判斷時,是這樣用:
<!-- 可以用 eq / ne / lt / le / gt / ge -->
{{if eq true .Var1 .Var2 .Var3}}
{{end}}
不過 Go 的 Template 沒辦法像 Django template 或 Jinja2 那麼的彈性,這部份得花點時間去熟悉跟習慣。
在 Django 裡,很常用的手法就是使用套嵌,把重複的部份抽取到基礎的模版,然後其他頁面就直接用 {% extends 'base.html' %} 來重複使用。BeeGo 裡則是用 {{ template "base.tpl" . }} ,接下來,就直接看程式碼比較快。
先在 views 下,新增一個 base.tpl (完整程式) ,關鍵的地方在於 {{ block "content" . }}{{ end }} 與 {{ block "scripts" . }}{{ end }} ,這兩個 block 表示要讓含括的頁面去填。這裡要注意一下 '.' ,這個 '.' 記得一定要寫,要不然會引用不到變數。
<!doctype html>
<html lang="en">
<head>
<!-- 省略 -->
</head>
<body>
<!-- 省略 -->
<main role="main" class="container">
<div class="starter">
{{ block "content" .}}{{end}}
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
{{ block "scripts" .}}{{end}}
</html>
接著改寫 views/user/index.tpl
{{ template "base.tpl" . }}
{{ define "content" }}
<h1>User list</h1>
{{if eq true .has_error}}
<div class="alert alert-danger" role="alert">
Error: {{.error}}
</div>
{{end}}
<p>Total records: {{.object_list_len}}</p>
<table class="table">
<thead>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Gender</th>
<th scope="col">Birthday</th>
</thead>
<tbody>
{{range $object := .object_list}}
<tr>
<th scope="row">{{$object.Id}}</th>
<td>{{$object.Name}}</td>
<td>{{$object.Gender}}</td>
<td>{{date $object.Birthday "Y-m-d"}}</td>
</tr>
{{end}}
</table>
{{ end }}
{{ define "scripts" }}
{{ end }}
這邊主要看幾個點:
View 的部份已經寫好了,現在還少一個 Controller 來處理顯示的邏輯。所以接下來直接複製之前產生的 controllers/user.go 來產生一個新的 controller
cp controllers/user.go controllers/myuser.go
接著做以下更動:
下方只保留關鍵的部份,完整程式在 github
package controllers
import (
"errors"
"my/hello/models"
"strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
)
// UserController operations for User
type MyUserController struct {
beego.Controller
}
// 省略
func (c *MyUserController) GetAll() {
// 省略
// query: k:v,k:v
if v := c.GetString("query"); v != "" {
for _, cond := range strings.Split(v, ",") {
kv := strings.SplitN(cond, ":", 2)
if len(kv) != 2 {
c.Data["has_error"] = true
c.Data["error"] = errors.New("Error: invalid query key/value pair")
return
}
k, v := kv[0], kv[1]
query[k] = v
}
}
logs.Debug("get all users")
l, err := models.GetAllUser(query, fields, sortby, order, offset, limit)
if err != nil {
logs.Error(err.Error())
c.Data["has_error"] = true
c.Data["error"] = err.Error()
} else {
logs.Debug("len(l)=", len(l))
c.Data["object_list_len"] = len(l)
c.Data["object_list"] = l
}
// 指定 Template
c.TplName = "user/index.tpl"
}
最後,就是在路由裡增加我們新增的 MyUserController
package routers
import (
"my/hello/controllers"
"github.com/astaxie/beego"
)
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/about", &controllers.AboutController{})
// 表示將 GET /myuser/ 指向 MyUserController 的 GetAll()
beego.Router("/myuser", &controllers.MyUserController{}, "get:GetAll")
}
至此,完成使用者列表的頁面。